﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace PatternLockControl.Code
{
    public static class LineHelper
    {
        /// <summary>
        /// Create line object 
        /// </summary>
        /// <param name="from">Point source</param>
        /// <param name="to">Point destination</param>
        /// <param name="strokeThickness">stroke thickness</param>
        /// <param name="selectedBrush">stroke brush</param>
        public static Line CreateLine(Point from, Point to, double strokeThickness, Brush selectedBrush)
        {
            return new Line
            {
                Stroke = selectedBrush,
                StrokeThickness = strokeThickness,
                X1 = from.X,
                X2 = to.X,
                Y1 = from.Y,
                Y2 = to.Y,
                IsHitTestVisible = false,
                StrokeDashCap = PenLineCap.Round,
                StrokeEndLineCap = PenLineCap.Round
            };
        }

        public static Line CreateDottedLine(Point from, Point to, double strokeThickness, Brush selectedBrush)
        {
            return new Line
            {
                Stroke = selectedBrush,
                StrokeThickness = strokeThickness,
                X1 = from.X,
                X2 = to.X,
                Y1 = from.Y,
                Y2 = to.Y,
                IsHitTestVisible = false,
                StrokeDashCap = PenLineCap.Square,
                StrokeEndLineCap = PenLineCap.Flat,
                StrokeDashArray = new DoubleCollection() { strokeThickness / 10, strokeThickness / 3}
            };
        }

        /// <summary>
        /// Create line object
        /// </summary>
        /// <param name="from">Point source</param>
        /// <param name="to">Point destination</param>
        /// <param name="strokeThickness">stroke thickness</param>
        /// <param name="selectedBrush">line's brush</param>
        /// <param name="parent">Grid parent</param>
        /// <returns></returns>
        public static Line CreateLine(Point from, Point to, double strokeThickness, Brush selectedBrush, int zIdx, Grid parent, LineType lineType)
        {
            if (null == parent)
                throw new ArgumentNullException("Parent");

            var line = lineType == LineType.SIMPLE ? CreateLine(from, to, strokeThickness, selectedBrush) : CreateDottedLine(from, to, strokeThickness, selectedBrush);

            line.SetValue(Grid.RowSpanProperty, parent.RowDefinitions.Count);
            line.SetValue(Grid.ColumnSpanProperty, parent.ColumnDefinitions.Count);
            //this zIdx has to be incrimental to show the latest line of top all
            line.SetValue(Canvas.ZIndexProperty, zIdx);
            return line;
        }

        /// <summary>
        /// Returns the Quadrant point required to start drawing a line
        /// </summary>
        /// <param name="startRow"></param>
        /// <param name="startColumn"></param>
        /// <param name="endRow"></param>
        /// <param name="endColumn"></param>
        /// <returns></returns>
        public static LineQuadrant FindQuadrantToDrawLineBW(int startRow, int startColumn, int endRow, int endColumn)
        {
            if (startRow == endRow)
            {
                if (startColumn < endColumn)
                    return LineQuadrant.RightMid;
                else
                    return LineQuadrant.LeftMid;
            }
            else if (startColumn == endColumn)
            {
                if (startRow < endRow)
                    return LineQuadrant.BottomMid;
                else
                    return LineQuadrant.TopMid;
            }
            else if (startRow < endRow) // bottom quadrant
            {
                if (startColumn < endColumn) // right quadrant
                    return LineQuadrant.BottomRight;
                else
                    return LineQuadrant.BottomLeft;
            }
            else // Top Quadrant
            {
                if (startColumn < endColumn) // right quadrant
                    return LineQuadrant.TopRight;
                else
                    return LineQuadrant.TopLeft;
            }
        }

        /// <summary>
        /// Returns a Point relative to given quadrant. This will be used to draw lines and shapes
        /// </summary>
        /// <param name="contentGrid"></param>
        /// <param name="shape"></param>
        /// <param name="quadrant"></param>
        /// <returns></returns>
        public static Point GetPtRelativeToQuadrant(Grid contentGrid, Border shape, LineQuadrant quadrant)
        {
            Point point;
            switch (quadrant)
            {
                case LineQuadrant.TopLeft:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(0, 0));
                case LineQuadrant.TopMid:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(shape.Width / 2, 0));
                case LineQuadrant.TopRight:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(shape.Width, 0));
                case LineQuadrant.RightMid:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(shape.Width, shape.Width / 2));
                case LineQuadrant.BottomRight:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(shape.Width, shape.Width));
                case LineQuadrant.BottomMid:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(shape.Width / 2, shape.Width));
                case LineQuadrant.BottomLeft:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(0, shape.Width));
                case LineQuadrant.LeftMid:
                    return point = shape.TransformToVisual(contentGrid).Transform(new Point(0, shape.Width / 2));
                default:
                    return new Point();
            }
        }

        public static LineType FindLineType(int startRow, int startColumn, int endRow, int endColumn)
        {
            //If difference in row and column is more then two then we need to draw overlapped line
            return Math.Abs(startRow - endRow) >= 2 || Math.Abs(startColumn - endColumn) >= 2 ? LineType.DOTTED : LineType.SIMPLE;
        }

        public static PointCollection GetPointsForPolygon(double brdWidth, LineQuadrant quad, Polygon poly)
        {
            double width = brdWidth / 6;
            double hyp = Math.Sqrt(2 * width * width);
            double mid = brdWidth / 2;
            double height = Math.Sqrt(width * width - (hyp / 2) * (hyp / 2)); //This height be being calculated for the TopMid, BottomMid, RightMid and LeftMide postion. 
            PointCollection pts = new PointCollection();
            switch (quad)
            {
                case LineQuadrant.TopLeft:
                    pts.Add(new Point(0, 0));
                    pts.Add(new Point(0, width));
                    pts.Add(new Point(width, 0));
                    break;
                case LineQuadrant.TopMid:
                    pts.Add(new Point(mid, -1 * height));
                    pts.Add(new Point(mid - hyp / 2, 0));
                    pts.Add(new Point(mid + hyp / 2, 0));
                    break;
                case LineQuadrant.TopRight:
                    pts.Add(new Point(brdWidth, 0));
                    pts.Add(new Point(brdWidth, width));
                    pts.Add(new Point(brdWidth - width, 0));
                    break;
                case LineQuadrant.RightMid:
                    pts.Add(new Point(brdWidth + height, mid));
                    pts.Add(new Point(brdWidth, mid - hyp / 2));
                    pts.Add(new Point(brdWidth, mid + hyp / 2));
                    poly.Margin = new Thickness(0, 0, -1 * height, 0); // Access margin added due to problem with polygon can't be shown ahead of it's parent +ve axes
                    break;
                case LineQuadrant.BottomRight:
                    pts.Add(new Point(brdWidth, brdWidth));
                    pts.Add(new Point(brdWidth, brdWidth - width));
                    pts.Add(new Point(brdWidth - width, brdWidth));
                    break;
                case LineQuadrant.BottomMid:
                    pts.Add(new Point(mid, brdWidth + height));
                    pts.Add(new Point(mid + hyp / 2, brdWidth));
                    pts.Add(new Point(mid - hyp / 2, brdWidth));
                    poly.Margin = new Thickness(0, 0, 0, -1 * height);
                    break;
                case LineQuadrant.BottomLeft:
                    pts.Add(new Point(0, brdWidth));
                    pts.Add(new Point(width, brdWidth));
                    pts.Add(new Point(0, brdWidth - width));
                    break;
                case LineQuadrant.LeftMid:
                    pts.Add(new Point(-1 * height, mid));
                    pts.Add(new Point(0, mid + hyp / 2));
                    pts.Add(new Point(0, mid - hyp / 2));
                    break;
                default:
                    pts.Add(new Point(0, 0));
                    pts.Add(new Point(0, 0));
                    pts.Add(new Point(0, 0));
                    break;
            }
            return pts;
        }
    }

    public enum LineQuadrant
    {
        TopLeft,
        TopMid,
        TopRight,
        RightMid,
        BottomRight,
        BottomMid,
        BottomLeft,
        LeftMid
    }

    public enum LineType
    {
        SIMPLE,
        DOTTED
    }
}
